import javax.swing.event.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import java.util.*;
import java.awt.*;
import java.io.*;

public class BoundingBoxEditor extends JPanel
{
	public static void main(String args[])
	{
		new BoundingBoxEditor();
	}
	
	private JButton addPoint;
	private JButton removePoint;
	private JButton clearAll;
	private JButton save;
	private JButton load;
	private JButton up;
	private JButton down;
	private JButton next;
	private JButton prev;
	
	private BufferedImage bgimage;
	private BufferedImage image;
	
	private int pixelSize;
	private boolean mode;
	
	private Color flash;
	private int count;
	
	private JPanel pointView;
	private ArrayList<Point> points;
	private Point current;
	private int index;
	private JList pointX;
	private JList pointY;
	
	public BoundingBoxEditor()
	{
		bgimage = new BufferedImage(800,600,BufferedImage.TYPE_INT_ARGB);
		points = new ArrayList<Point>();
		index = 0;
		pixelSize = 8;
		mode = true;
		
		flash = Color.WHITE;
		
		JFrame frame = new JFrame();
		frame.setSize(800,690);
		frame.setDefaultCloseOperation(3);
		
		JPanel buttons = new JPanel();
		
		SpringLayout bsl = new SpringLayout();
		
		buttons.setLayout(bsl);
		buttons.setPreferredSize(new Dimension(794,63));
		buttons.setBorder(BorderFactory.createTitledBorder("Control"));
		
		addPoint = new JButton("Add Points");
			addPoint.setPreferredSize(new Dimension(140,30));
			addPoint.addActionListener(new AddAction());
			bsl.putConstraint(SpringLayout.NORTH,addPoint,0,SpringLayout.NORTH,buttons);
			bsl.putConstraint(SpringLayout.WEST,addPoint,20,SpringLayout.WEST,buttons);
		removePoint = new JButton("Remove Points");
			removePoint.setPreferredSize(new Dimension(140,30));
			removePoint.addActionListener(new RemoveAction());
			bsl.putConstraint(SpringLayout.WEST,removePoint,10,SpringLayout.EAST,addPoint);
		clearAll = new JButton("Clear All Points");
			clearAll.setPreferredSize(new Dimension(140,30));
			clearAll.addActionListener(new ClearAction());
			bsl.putConstraint(SpringLayout.WEST,clearAll,10,SpringLayout.EAST,removePoint);
		save = new JButton("Save");
			save.setPreferredSize(new Dimension(140,30));
			save.addActionListener(new SaveAction());
			bsl.putConstraint(SpringLayout.WEST,save,10,SpringLayout.EAST,clearAll);
		load = new JButton("Load");
			load.setPreferredSize(new Dimension(140,30));
			load.addActionListener(new LoadAction());
			bsl.putConstraint(SpringLayout.WEST,load,10,SpringLayout.EAST,save);
			
			buttons.add(addPoint);
			buttons.add(removePoint);
			buttons.add(clearAll);
			buttons.add(save);
			buttons.add(load);
		
		pointView = new JPanel();
		SpringLayout psl = new SpringLayout();
		
		pointView.setLayout(psl);
		pointView.setPreferredSize(new Dimension(150,600));
		pointView.setBorder(BorderFactory.createTitledBorder("Points"));
		
		pointX = new JList();
			pointX.setPreferredSize(new Dimension(65,530));
			pointX.setFixedCellHeight(20);
			pointX.setFixedCellWidth(65);
		pointY = new JList();
			pointY.setPreferredSize(new Dimension(65,530));
			pointY.setFixedCellHeight(20);
			pointY.setFixedCellWidth(65);
		
		up = new JButton("Up");
			up.setPreferredSize(new Dimension(68,20));
			up.addActionListener(new UpAction());
		down = new JButton("Down");
			down.setPreferredSize(new Dimension(68,20));
			down.addActionListener(new DownAction());
		next = new JButton("Next");
			next.setPreferredSize(new Dimension(68,20));
			next.addActionListener(new MvmntListen());
		prev = new JButton("Prev");
			prev.setPreferredSize(new Dimension(68,20));
			prev.addActionListener(new MvmntListen());
			
			psl.putConstraint(SpringLayout.NORTH,pointX,0,SpringLayout.NORTH,pointView);
			psl.putConstraint(SpringLayout.WEST,pointX,0,SpringLayout.WEST,pointView);
			
			psl.putConstraint(SpringLayout.NORTH,pointY,0,SpringLayout.NORTH,pointView);
			psl.putConstraint(SpringLayout.EAST,pointY,0,SpringLayout.EAST,pointView);
			
			psl.putConstraint(SpringLayout.NORTH,up,5,SpringLayout.SOUTH,pointX);
			psl.putConstraint(SpringLayout.WEST,up,0,SpringLayout.WEST,pointView);
			
			psl.putConstraint(SpringLayout.NORTH,down,5,SpringLayout.SOUTH,pointY);
			psl.putConstraint(SpringLayout.EAST,down,0,SpringLayout.EAST,pointView);
			
			psl.putConstraint(SpringLayout.NORTH,next,1,SpringLayout.SOUTH,up);
			psl.putConstraint(SpringLayout.WEST,next,0,SpringLayout.WEST,pointView);
			
			psl.putConstraint(SpringLayout.NORTH,prev,1,SpringLayout.SOUTH,down);
			psl.putConstraint(SpringLayout.EAST,prev,0,SpringLayout.EAST,pointView);
			
			pointView.add(pointX);
			pointView.add(pointY);
			pointView.add(up);
			pointView.add(down);
			pointView.add(next);
			pointView.add(prev);
		
		SpringLayout sl = new SpringLayout();
		setLayout(sl);
		
		sl.putConstraint(SpringLayout.NORTH,pointView,0,SpringLayout.NORTH,this);
		sl.putConstraint(SpringLayout.EAST,pointView,0,SpringLayout.EAST,this);
		
		sl.putConstraint(SpringLayout.NORTH,buttons,600,SpringLayout.NORTH,this);
		sl.putConstraint(SpringLayout.WEST,buttons,0,SpringLayout.WEST,this);
		
		add(pointView);
		add(buttons);
		
		addMouseListener(new MouseListen());
		frame.setContentPane(this);
		frame.setResizable(false);
		frame.setVisible(true);
		
		javax.swing.Timer t = new javax.swing.Timer(10,new RefreshListener());
		t.start();
	}
	
	public void paintComponent(Graphics g)
	{
		drawBGImage();
		g.drawImage(bgimage,0,0,null);
		
		if(image != null)
		{
			for(Point p : points)
			{
				int xloc = (getWidth()-150)/pixelSize/2-image.getWidth(null)/2+1+p.x;
				int yloc = getHeight()/pixelSize/2-image.getHeight(null)/2+1+p.y;
				
				if(p == current)
					fillPixel(xloc,yloc,new Color(0,flash.getGreen(),0),g);
				else
					fillPixel(xloc,yloc,flash,g);
			}
		}
		
		if(flash == Color.WHITE && count-- < 0)
		{
			flash = Color.BLACK;
			count = 10;
		}
		if(flash == Color.BLACK && count-- < 0)
		{
			flash = Color.WHITE;
			count = 10;
		}
	}
	
	private void fillPixel(int x, int y, Color c, Graphics g)
	{
		g.setColor(c);
		g.fillRect(x*pixelSize+1,y*pixelSize+1,pixelSize-1,pixelSize-1);
	}
	
	private void drawBGImage()
	{
		Graphics g = bgimage.getGraphics();
		
		g.setColor(Color.BLACK);
		
		for(int x = 0; x < (getWidth()-150)-pixelSize; x += pixelSize)
			for(int y = 0; y < getHeight()-pixelSize; y += pixelSize)
				g.drawRect(x,y,pixelSize,pixelSize);
		
		for(int x = 0; x < (getWidth()-150)/pixelSize; x++)
		{
			for(int y = 0; y < getHeight()/pixelSize; y++)
			{
				fillPixel(x,y,Color.GRAY,g);
				
				if(image != null && y > getHeight()/pixelSize/2-image.getHeight(null)/2 && y < getHeight()/pixelSize/2+image.getHeight(null)/2+1 &&
				   x > (getWidth()-150)/pixelSize/2-image.getWidth(null)/2 && x < (getWidth()-150)/pixelSize/2+image.getWidth(null)/2+1)
				{
					int xloc = x-(getWidth()-150)/pixelSize/2+image.getWidth(null)/2-1;
					int yloc = y-getHeight()/pixelSize/2+image.getHeight(null)/2-1;
					
					String s = Integer.toBinaryString(image.getRGB(xloc,yloc++));
					
					Color temp = new Color(0,0,0,0);
					
					if(s.length() > 1)
					{
						int a = Integer.parseInt(s.substring(0,8),2);
						int r = Integer.parseInt(s.substring(8,16),2);
						int gr = Integer.parseInt(s.substring(16,24),2);
						int bl = Integer.parseInt(s.substring(24),2);
						temp = new Color(r,gr,bl);
					}
					
					fillPixel(x,y,temp,g);
				}
			}
		}
	}
	
	class LoadAction implements ActionListener
	{
		public void actionPerformed(ActionEvent ae)
		{
			JFileChooser jfc = new JFileChooser();
			jfc.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter("PNG & RedWorld Entity files","png","rwe"));
			int a = jfc.showOpenDialog(null);
			
			if(a == JFileChooser.APPROVE_OPTION)
			{
				File f = jfc.getSelectedFile();
				
				if(f.getName().substring(f.getName().lastIndexOf(".")).equals(".png"))
					image = ImageToolkit.loadImage(f.getAbsolutePath(),false);
				if(f.getName().substring(f.getName().lastIndexOf(".")).equals(".rwe"))
				{
					try
					{
						FileInputStream fis = new FileInputStream(f);
						
						byte b[] = new byte[(int)f.length()];
						
						fis.read(b);
						
						int x;
						for(x = 0; x < b.length; x++)
							if(b[x] == -119 && b[x+1] == 'P' && b[x+2] == 'N' && b[x+3] == 'G')
								break;
						
						for(int k = 0; k < x; k+=2)
							points.add(new Point(b[k],b[k+1]));
						
						byte imageByte[] = new byte[b.length-x];
						System.arraycopy(b,x,imageByte,0,imageByte.length);
						
						image = ImageToolkit.loadImage(imageByte,false);
					}
					catch(Exception e){}
				}
			}
		}
	}
	
	class SaveAction implements ActionListener
	{
		public void actionPerformed(ActionEvent ae)
		{
			JFileChooser jfc = new JFileChooser();
			jfc.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter("RedWorld Entity file","rwe"));
			int a = jfc.showSaveDialog(null);
			
			if(a == JFileChooser.APPROVE_OPTION)
			{
				File png = new File(jfc.getSelectedFile().getAbsolutePath()+".png");
				byte b[] = new byte[(int)png.length()+points.size()*2];
				
				int k = 0;
				
				for(Point p : points)
				{
					b[k++] = (byte)p.x;
					b[k++] = (byte)p.y;
				}
				
				try
				{
					FileInputStream fis = new FileInputStream(png);
					
					byte imageByte[] = new byte[(int)png.length()];
					
					fis.read(imageByte);
					fis.close();
					
					System.arraycopy(imageByte,0,b,k,imageByte.length);
					
					FileOutputStream fos = new FileOutputStream(new File(jfc.getSelectedFile().getAbsolutePath()+".rwe"));
					
					fos.write(b);
					fos.flush();
				}
				catch(Exception e){}
			}
		}
	}
	
	class AddAction implements ActionListener
	{
		public void actionPerformed(ActionEvent ae)
		{
			mode = true;
		}
	}
	
	class RemoveAction implements ActionListener
	{
		public void actionPerformed(ActionEvent ae)
		{
			mode = false;
		}
	}
	
	class ClearAction implements ActionListener
	{
		public void actionPerformed(ActionEvent ae)
		{
			points = new ArrayList<Point>();
		}
	}
	
	class RefreshListener implements ActionListener
	{
		public void actionPerformed(ActionEvent ae)
		{
			repaint();
			
			Integer xval[] = new Integer[points.size()];
			Integer yval[] = new Integer[points.size()];
			
			for(int x = 0; x < points.size(); x++)
			{
				xval[x] = points.get(x).x;
				yval[x] = points.get(x).y;
			}
			
			pointX.setListData(xval);
			pointY.setListData(yval);
			
			pointView.getGraphics().drawLine(70,30+index*20,78,30+index*20);
		}
	}
	
	class UpAction implements ActionListener
	{
		public void actionPerformed(ActionEvent ae)
		{
			if(index == 0)
				return;
			
			points.add(index-1,points.remove(index));
			index--;
			System.out.println(index);
		}
	}
	
	class DownAction implements ActionListener
	{
		public void actionPerformed(ActionEvent ae)
		{
			if(index == points.size()-1)
				return;
			
			points.add(index+1,points.remove(index));
			index++;
			System.out.println(index);
		}
	}
	
	class MouseListen extends MouseAdapter
	{
		public void mouseReleased(MouseEvent e)
		{
			if(image != null)
			{
				int xloc = e.getX()/pixelSize-(getWidth()-150)/pixelSize/2+image.getWidth(null)/2-1;
				int yloc = e.getY()/pixelSize-getHeight()/pixelSize/2+image.getHeight(null)/2-1;
				
				if(mode)
					points.add(new Point(xloc,yloc));
				else
					points.remove(new Point(xloc,yloc));
				
				current = points.get(0);
			}
		}
	}
	
	class MvmntListen implements ActionListener
	{
		public void actionPerformed(ActionEvent ae)
		{
			if(ae.getSource() == next)
				index++;
			else
				index--;
			
			index = Math.max(0,index);
			index = Math.min(points.size()-1,index);
			
			pointY.setSelectedIndex(index);
			pointX.setSelectedIndex(index);
			
			current = points.get(index);
		}
	}
}